/**
 * @file    inf_heating_pad.c
 * @author  yhy
 * @brief   加热垫模块源文件
 * @version 1.00
 * @date    2025-08-05
 *
 * @copyright Copyright (c) 2025
 *
 */
#include "inf_heating_pad.h"

#include "drv_gpio.h"
#include "drv_pwm.h"
#include "inf_ntc.h"
#include "common_debug.h"

#include <string.h>

#define HEATL_PWM_INSTANCE PWM_INSTANCE_IPWM0
#define HEATL_PWM_CHANNEL  PWM_CHANNEL_1
#define HEATL_PWM_PIN_NUM  GET_PIN_NUM(A, 11)
#define NTC_ADC_BUF_IDX    3U

static result_e inf_heat_pwm_config(void);

/* 加热垫系统实例 */
static heat_system_t heat_system;

extern int32_t adc_real_data_list[];

/**
 * @brief 初始化加热垫系统
 *
 * @return result_e 初始化结果, RESULT_STATUS_OK表示成功, 其他值表示失败
 */
result_e inf_heat_init(void)
{
    result_e result = inf_heat_pwm_config();
    if (result != RESULT_STATUS_OK) {
        return result;
    }

    memset(&heat_system, 0, sizeof(heat_system_t));

    heat_system.heats[HEAT_IDX_HEATL].pwm_config.instance = HEATL_PWM_INSTANCE;
    heat_system.heats[HEAT_IDX_HEATL].pwm_config.pwm_ch   = HEATL_PWM_CHANNEL;
    heat_system.heats[HEAT_IDX_HEATL].gear                = HEAT_GEAR_CLOSE;
    heat_system.heats[HEAT_IDX_HEATL].last_gear           = HEAT_GEAR_CLOSE;
    heat_system.heats[HEAT_IDX_HEATL].fault               = HEAT_FAULT_NONE;
    heat_system.heats[HEAT_IDX_HEATL].blocked             = false;
    heat_system.ntc_enable                                = false;

    heat_system.system_enable = false;

    /* 初始化加热垫PWM */
    snf_drv_pwm_set_duty(HEATL_PWM_INSTANCE, HEATL_PWM_CHANNEL, HEAT_GEAR_CLOSE);

    /* 初始化NTC模块 */
    CHECK_RESULT(inf_ntc_init(), "NTC module init failed");

    return result;
}

/**
 * @brief 设置加热垫系统使能状态
 *
 * @param   enable      使能状态
 * @return  result_e    设置结果, RESULT_STATUS_OK表示成功, 其他值表示失败
 */
void inf_heat_set_system_enable(bool enable)
{
    heat_system.system_enable = enable;

    /* 如果是关闭系统, 失能所有的加热垫 */
    if (!enable) {
        for (uint8_t i = 0; i < HEAT_IDX_MAX; ++i) {
            heat_system.heats[i].gear    = HEAT_GEAR_CLOSE;
            heat_system.heats[i].blocked = false;
            heat_system.heats[i].fault   = HEAT_FAULT_NONE;
        }
    }
}

/**
 * @brief 设置加热垫档位
 *
 * @param   idx         加热垫索引
 * @param   gear        档位
 * @return  result_e    设置结果, RESULT_STATUS_OK表示成功, 其他值表示失败
 */
result_e inf_heat_set_gear(heat_idx_e idx, heat_gear_e gear)
{
    if (idx >= HEAT_IDX_MAX || gear >= HEAT_GEAR_MAX) {
        return RESULT_STATUS_INVALID_PARAM;
    }

    /* 系统使能检查 */
    if (!heat_system.system_enable && gear != HEAT_GEAR_CLOSE) {
        return RESULT_STATUS_NOT_INITIALIZED;
    }

    heat_system.heats[idx].gear = gear;

    return RESULT_STATUS_OK;
}

/**
 * @brief 设置加热垫故障状态
 *
 * @param   idx         加热垫索引
 * @param   fault       故障状态
 * @return  result_e    设置结果, RESULT_STATUS_OK表示成功, 其他值表示失败
 */
result_e inf_heat_set_fault(heat_idx_e idx, heat_fault_e fault)
{
    if (idx >= HEAT_IDX_MAX || fault >= HEAT_FAULT_MAX) {
        return RESULT_STATUS_INVALID_PARAM;
    }

    heat_system.heats[idx].fault = fault;

    return RESULT_STATUS_OK;
}

/**
 * @brief 检查加热垫互锁状态
 *
 * @param idx       加热垫索引
 * @param blocked   互锁状态
 * @return result_e 检查结果, RESULT_STATUS_OK表示成功, 其他值表示失败
 */
result_e inf_heat_check_interlock(heat_idx_e idx, bool blocked)
{
    if (idx >= HEAT_IDX_MAX) {
        return RESULT_STATUS_INVALID_PARAM;
    }

    /* 如果加热系统激活, 并且加热垫不是关闭状态, 则设置阻塞 */
    if (blocked && heat_system.system_enable && heat_system.heats[idx].gear != HEAT_GEAR_CLOSE) {
        heat_system.heats[idx].gear = HEAT_GEAR_CLOSE;
    }

    heat_system.heats[idx].blocked = blocked;

    return RESULT_STATUS_OK;
}

/**
 * @brief 获取加热垫档位
 *
 * @param   idx         加热垫索引
 * @return  heat_gear_e  档位
 */
heat_gear_e inf_heat_get_gear(heat_idx_e idx)
{
    if (idx >= HEAT_IDX_MAX) {
        return HEAT_GEAR_MAX;
    }

    return heat_system.heats[idx].gear;
}

/**
 * @brief 获取加热垫故障状态
 *
 * @param   idx         加热垫索引
 * @return  heat_fault_e 故障状态
 */
heat_fault_e inf_heat_get_fault(heat_idx_e idx)
{
    if (idx >= HEAT_IDX_MAX) {
        return HEAT_FAULT_MAX;
    }

    return heat_system.heats[idx].fault;
}

/**
 * @brief 获取加热垫互锁状态
 *
 * @param   idx         加热垫索引
 * @return  true        互锁状态为阻塞
 * @return  false       互锁状态为非阻塞
 */
bool inf_heat_get_bolcked_status(heat_idx_e idx)
{
    if (idx >= HEAT_IDX_MAX) {
        return false;
    }

    return heat_system.heats[idx].blocked;
}

/**
 * @brief 加热垫系统处理函数，需要在调度器中调度, 50～100ms调度一次
 *
 */
void inf_heat_handle(void)
{
    if (!heat_system.system_enable) {
        return;
    }

    for (uint8_t i = 0; i < HEAT_IDX_MAX; ++i) {
        heat_t     *heat     = &heat_system.heats[i];
        heat_gear_e new_gear = heat->gear;

        /* 检查互锁状态 */
        if (heat->blocked && heat->gear != HEAT_GEAR_CLOSE) {
            new_gear = HEAT_GEAR_CLOSE;
        }

        /* 检查故障状态 */
        if (heat->fault != HEAT_FAULT_NONE && heat->gear != HEAT_GEAR_CLOSE) {
            new_gear = HEAT_GEAR_CLOSE;
        }

        /* 使能NTC */
        if (heat_system.ntc_enable && heat->gear != HEAT_GEAR_CLOSE) {
            int32_t adc_value       = adc_real_data_list[NTC_ADC_BUF_IDX];
            int16_t pid_output_duty = inf_ntc_get_pid_output(new_gear, adc_value);

            snf_drv_pwm_set_duty((snf_pwm_instance_e)heat->pwm_config.instance,
                                 (snf_pwm_channel_e)heat->pwm_config.pwm_ch, pid_output_duty);

            heat->last_gear = new_gear;
        }
        else {

            /* 只有档位发生变化时才更新PWM输出 */
            if (new_gear != heat->last_gear) {
                snf_drv_pwm_set_duty((snf_pwm_instance_e)heat->pwm_config.instance,
                                     (snf_pwm_channel_e)heat->pwm_config.pwm_ch, new_gear);
                heat->last_gear = new_gear;
            }
        }

        heat->gear = new_gear;
    }
}

/**
 * @brief 初始化加热垫PWM
 *
 * @return result_e 初始化结果, RESULT_STATUS_OK表示成功, 其他值表示失败
 */
static result_e inf_heat_pwm_config(void)
{
    snf_pwm_config_t heatl_pwm_config = {
        .instance     = HEATL_PWM_INSTANCE,
        .channel_list = { HEATL_PWM_CHANNEL },
        .channel_num  = 1,
        .freq         = PWM_FREQ_20KHZ,
        .pin_num_list = { HEATL_PWM_PIN_NUM },
    };
    result_e result = snf_drv_pwm_init(&heatl_pwm_config);
    if (result != RESULT_STATUS_OK) {
        return result;
    }

    return RESULT_STATUS_OK;
}
